package ru.emms.codemeter.tables;

import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: nastya.kuz
 * Date: 29.07.2010
 * Time: 17:29:02
 * Производиться управление структурой иерархии заголовков столбцов.
 * Имена столбцов могут быть одиночными, могут объединяться в группу, группы в свою очередь,
 * также могут быть объединены в группу более высокого уровня и т.д.
 */
public class ColumnGroup {

    private TableCellRenderer renderer;
    private ArrayList<ColumnGroup> groups;
    private ArrayList<TableColumn> columns;
    private String header;
    private int margin = 0;

    public ColumnGroup(String header) {
        this(null, header);
    }

    /**
     * @param renderer    объект для отрисовывания ячейки таблицы
     * @param headerValue значение заголовка столбца
     */
    public ColumnGroup(TableCellRenderer renderer, String headerValue) {
        if (renderer == null) {
            this.renderer = new DefaultTableCellRenderer() {
                public Component getTableCellRendererComponent(JTable table, Object value,
                    boolean isSelected, boolean hasFocus, int row, int column) {
                    JTableHeader header = table.getTableHeader();
                    if (header != null) {
                        setForeground(header.getForeground());
                        setBackground(header.getBackground());
                        setFont(header.getFont());
                    }
                    setHorizontalAlignment(JLabel.CENTER);
                    setText((value == null) ? "" : value.toString());
                    setBorder(UIManager.getBorder("TableHeader.cellBorder"));
                    return this;
                }
            };
        } else {
            this.renderer = renderer;
        }
        this.header = headerValue;
        groups = new ArrayList<ColumnGroup>();
        columns = new ArrayList<TableColumn>();
    }

    /**
     * Добавляет к списку столбцов
     * столбец типа TableColumn
     *
     * @param column Добавляемый столбец
     */
    public void add(TableColumn column) {
        if (column != null) {
            columns.add(column);
        }
    }

    /**
     * Добавляет к списку групп
     * группу столбцов типа ColumnGroup
     *
     * @param columnGroup Добавляемая группа
     */
    public void add(ColumnGroup columnGroup) {
        if (columnGroup != null) {
            groups.add(columnGroup);
        }
    }

    /**
     * определяет набор групп, к которым принадлежит столбец
     *
     * @param column      проверяемый столбец
     * @param columnGroup при рекурсивном поиске хранит группу, в которой ищем
     * @return набор групп, к которым принадлежит данный столбец
     *         или null, если столбец не принадлежит ни одной группе
     */
    public List<ColumnGroup> getColumnGroups(TableColumn column, List<ColumnGroup> columnGroup) {
        columnGroup.add(this);
        if (this.columns.contains(column)) {
            return columnGroup;
        }
        for (ColumnGroup group : groups) {
            ArrayList<ColumnGroup> listCopy = new ArrayList<ColumnGroup>(columnGroup);
            List<ColumnGroup> resultGroup = group.getColumnGroups(column, listCopy);
            if (resultGroup != null) {
                return resultGroup;
            }
        }
        return null;
    }

    public TableCellRenderer getHeaderRenderer() {
        return renderer;
    }

    public String getHeaderValue() {
        return header;
    }

    /**
     * Определяет размеры таблицы table
     *
     * @param table Таблица
     * @return размер таблицы
     */
    public Dimension getSize(JTable table) {
        Component component = renderer.getTableCellRendererComponent(
            table, getHeaderValue(), false, false, -1, -1);
        int height = component.getPreferredSize().height;
        int width = 0;
        for (Object group : groups) {
            Dimension sizeTable = ((ColumnGroup) group).getSize(table);
            width += sizeTable.width;
        }
        for (TableColumn column : columns) {
            width += column.getWidth();
            width += margin;
        }
        return new Dimension(width, height);
    }

    /**
     * устанавливает расстояние между ячейками столбца
     *
     * @param margin рассояние между ячейками столбца
     */
    public void setColumnMargin(int margin) {
        this.margin = margin;
        for (ColumnGroup group : groups) {
            group.setColumnMargin(margin);
        }
    }
}